/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dao;

import common.Application;
import common.EntityPresentation;
import common.Initializer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import parsers.ResultSetWrapParser;
import parsers.SqlParser;
import templates.PropertyTemplate;
import templates.Template;
import utils.GenericPair;
import utils.ResultSetWrap;

/**
 *
 * @author Alejandro
 */
public class EntityCash {

    private static boolean isWorking = false;
    private static Collection<GenericPair<Short, ResultSetWrap>> rawCash = new LinkedList<GenericPair<Short, ResultSetWrap>>();
    private static Collection<Entity> cash = new LinkedList<Entity>();

    public static void capture() {
        if (!isWorking) {
            isWorking = true;
        }
    }

    public static void release() {
        if (isWorking) {
            cash.clear();
            rawCash.clear();
            isWorking = false;
        }
    }

    public static boolean canUse() {
        return isWorking;
    }

    public static Iterable<Short> analyze(short uid) {
        if (!isWorking) {
            return null;
        }
        List<Short> list = new LinkedList<Short>();
        list.add(uid);
        Template t = Application.getInstance().getTemplate(uid);
        for (PropertyTemplate pt : t.getPropertyTemplateCollection()) {
            if (pt.isForeignKey()) {
                if (pt.getExternalUid() != uid) {
                    List<Short> nested = (List<Short>) analyze(pt.getExternalUid());
                    Collections.reverse(nested);
                    for (short j : nested) {
                        list.add(j);
                    }
                }
            }
        }
        Collections.reverse(list);
        return list;
    }

    public static void setRawCash(short uid, ResultSetWrap rs) {
        if (isWorking) {
            rawCash.add(new GenericPair(uid, rs));
        }
    }

    public static Entity findEntity(short uid, String primaryKey) {
        if (!isWorking) {
            return null;
        }
        Entity obj = null;
        for (Entity e : cash) {
            if (e.getUid() == uid && e.getPrimaryKeyValue().equals(primaryKey)) {
                obj = e;
                break;
            }
        }
        return obj;
    }

    private static Iterable<ResultSetRow> getObjects(Iterable<ResultSetRow> container, String foreignKey, short foreignKeyUid, short primaryKeyUid) {
        Collection<ResultSetRow> newArray = new LinkedList<ResultSetRow>();

        for (ResultSetRow rsr: container) {
            if (rsr.getValue(foreignKeyUid).equals(foreignKey)) {
                newArray.add(rsr);
                Iterable<ResultSetRow> dependants = getObjects(container, rsr.getValue(primaryKeyUid), foreignKeyUid, primaryKeyUid);
                for (ResultSetRow rsr2: dependants) {
                    newArray.add(rsr2);
                }
            }
        }

        return newArray;
    }

    private static Iterable<ResultSetRow> orderHierarchyResultSet(short uid, ResultSetWrap rs) throws SQLException {
        Iterable<ResultSetRow> container = null;
        Collection<ResultSetRow> array = new LinkedList<ResultSetRow>();
        while (rs.next()) {
            array.add(new ResultSetRow(rs));
        }

        Template t = Application.getInstance().getTemplate(uid);
        String defForeignKey = t.getPropertyTemplate(t.getSelfForeignKeyUid()).getNullValue();

        container = getObjects(array, defForeignKey, t.getSelfForeignKeyUid(), t.getPrimaryKeyUid());

        return container;
    }

    public static void parse() throws SQLException {
        if (!isWorking) {
            return;
        }
        for (GenericPair<Short, ResultSetWrap> pair : rawCash) {
            Template t = Application.getInstance().getTemplate(pair.getFirst());
            ResultSetWrap rs = pair.getSecond();
            if (t.getSelfForeignKeyUid() == 0) {
                Initializer in = new ResultSetWrapParser(rs);
                while (rs.next()) {
                    Entity e = new Entity(pair.getFirst());
                    e.parse(in);
                    cash.add(e);
                }
            } else {
                ResultSetRow.bind(pair.getFirst());
                for (ResultSetRow rsr: orderHierarchyResultSet(pair.getFirst(), rs)) {
                    Entity e = new Entity(pair.getFirst());
                    e.parse(new EntityParser(rsr));
                    cash.add(e);
                }
            }
        }
    }

    public static Iterable<EntityPresentation> getCollection(short uid) {
        Collection<EntityPresentation> container = new LinkedList<EntityPresentation>();
        for (Entity e : cash) {
            if (e.getUid() == uid) {
                container.add(e);
            }
        }
        return container;
    }
}
